package com.ctc;

public class DataPacket
{
    /*
     * 数据包头       2字节         固定0xABCD
     * P位           1字节         默认从0开始,用于1块主板多个P位
     * 命令标识       2字节         具体功能的标识
     * 事务ID         4字节         用于防止重发
     * 长度           1字节         数据字段的长度
     * 数据           n字节,n=长度   功能携带的参数
     * 校验           4字节         CRC32国际标准算法
     */

    /**
     * 数据包头       2字节         固定0xABCD
     */
    public static final byte[] DATA_HEAD = new byte[]{(byte) 0xAB, (byte) 0xCD};

    /**
     * 数据包空包长度
     */
    public static final int PACKET_LENGTH = 14;

    /**
     * P位           1字节         默认从0开始,用于1块主板多个P位
     */
    private byte player;

    /**
     * 事务编号       4字节         用于防止重发
     */
    private long transactionId;

    /**
     * 指令           2字节         具体功能的标识
     */
    private byte[] inst;

    /**
     * 数据包CRC校验   4字节         CRC32国际标准算法
     */
    private byte[] packetCRC;

    /**
     * 数据体         n字节,n=长度   功能携带的参数
     */
    private byte[] data;

    /**
     * 构造，生成一个数据包，用来发送
     *
     * @param player        P位           1字节         默认从0开始,用于1块主板多个P位
     * @param inst          指令           2字节         具体功能的标识
     * @param transactionId 事务编号       4字节         用于防止重发
     * @param data          数据体         n字节,n=长度   功能携带的参数
     */
    public DataPacket(byte player, byte[] inst, long transactionId, byte... data)
    {
        this.player = player;
        this.transactionId = transactionId;
        this.inst = inst;
        this.data = data != null ? data : new byte[0];
        this.packetCRC = CRC.uint32ToBytes(CRC.crc32(getVerifyPacketData()));
    }

    /**
     * 获取P位
     *
     * @return P位
     */
    public byte getPlayer()
    {
        return player;
    }

    /**
     * 获取数据包长度
     *
     * @return 数据长度
     */
    public byte getDataLength()
    {
        return (byte) (data != null ? data.length : 0);
    }

    /**
     * 获取事务ID
     *
     * @return 事务ID
     */
    public long getTransactionId()
    {
        return transactionId;
    }

    /**
     * 获取指令
     *
     * @return 指令
     */
    public byte[] getInst()
    {
        return inst;
    }

    /**
     * 获取数据包CRC校验
     *
     * @return 数据包CRC校验
     */
    public byte[] getPacketCRC()
    {
        return packetCRC;
    }

    /**
     * 获取数据体
     *
     * @return 数据体
     */
    public byte[] getData()
    {
        return data;
    }

    /**
     * 返回此包需要校验的数据
     */
    private byte[] getVerifyPacketData()
    {
        byte[] result = new byte[10 + (data != null ? data.length : 0)];
        System.arraycopy(DataPacket.DATA_HEAD, 0, result, 0, DataPacket.DATA_HEAD.length); // 0-1
        result[2] = player; // 2
        System.arraycopy(inst, 0, result, 3, inst.length); // 3-4
        System.arraycopy(CRC.uint32ToBytes(transactionId), 0, result, 5, 4); // 5-8
        result[9] = getDataLength(); // 9
        if (data != null && data.length > 0)
        {
            System.arraycopy(data, 0, result, 10, data.length); // 10-N
        }
        return result;
    }

    /**
     * 将数据包输出为数组
     *
     * @return 数据包数组
     */
    public byte[] toArray()
    {
        byte dataLength = getDataLength();
        byte[] sendData = new byte[PACKET_LENGTH + dataLength];
        System.arraycopy(DataPacket.DATA_HEAD, 0, sendData, 0, DataPacket.DATA_HEAD.length); // 0-1
        sendData[2] = player; // 2
        System.arraycopy(inst, 0, sendData, 3, inst.length); // 3-4
        System.arraycopy(CRC.uint32ToBytes(transactionId), 0, sendData, 5, 4); // 5-8
        sendData[9] = dataLength; // 9
        if (data != null && data.length > 0)
        {
            System.arraycopy(data, 0, sendData, 10, data.length); // 10-N
        }
        System.arraycopy(packetCRC, 0, sendData, 10 + dataLength, 4); // 10+N
        return sendData;
    }

    /**
     * 根据数据格式化一个包,如果数据长度小于最小返回null
     *
     * @param data 数据
     * @return 格式化后的包
     */
    public static DataPacket format(byte[] data)
    {
        byte[] da = new byte[data[9]];
        System.arraycopy(data, 10, da, 0, da.length);
        // byte[] data=
        return new DataPacket(data[2], new byte[]{data[3], data[4]}, CRC.bytesToUint32(data[5], data[6], data[7], data[8]), da);
    }
}